import MBase from "../utils/m-base";
import MFile from "../utils/m-file";
import MCmder from "./m-cmder";
import { IGlobal } from "../m-types";

/**动态构造器 */
type WriterBuilder = new (parm: IGlobal) => MWriter;

/**文件书写器基类 */
export default abstract class MWriter {
  /**是否已加载 */
  private static loaded: boolean = false;
  /**子类注册表 */
  private static writers: Record<string, WriterBuilder> = {};
  /**顶级参数 */
  private _parm = {} as IGlobal;
  /**顶级参数 */
  protected get parm() {
    return this._parm;
  }
  /**解析后的数据 */
  protected get data() {
    return this.parm.result;
  }

  protected get dir() {
    const { apiPath } = this.parm;
    return apiPath;
  }

  /** 注册书写器类 */
  public static register(writerName: string, writer: WriterBuilder) {
    MWriter.writers[writerName] = writer;
  }

  /** 动态加载所有子类 */
  private static async loadWriters() {
    const path = MFile.joinDirPath(__dirname, "../subWriters");
    const files = await MFile.readDir(path);
    for (const file of files) {
      if (!file.endsWith(".ts") && !file.endsWith(".js")) continue;
      require(MFile.joinDirPath(path, file));
    }
    MWriter.loaded = true;
  }

  /**创建书写器 */
  public static async write(parm: IGlobal) {
    const { writerName } = parm;
    if (!MWriter.loaded) await MWriter.loadWriters();
    const WriterClass = MWriter.writers[writerName];
    if (!WriterClass) throw new Error(`未找到书写器: ${writerName}`);
    const writer = new WriterClass(parm);
    await writer.clearFiles();
    await Promise.all([
      writer.writeEnums(),
      writer.writeModels(),
      writer.writeMethods(),
    ]);
  }

  /**实例化书写器 */
  constructor(parm: IGlobal) {
    this._parm = parm;
  }

  /**书写枚举 */
  protected abstract writeEnums(): Promise<void>;

  /**书写模型 */
  protected abstract writeModels(): Promise<void>;

  /**书写请求函数 */
  protected abstract writeMethods(): Promise<void>;

  /**获取文件顶部提示内容 */
  protected getFileTips() {
    const cmd = MCmder.encodeArgs(this.parm);
    return [
      "/* eslint-disable */",
      ...MBase.toCommonNote("此文件代码由接口发布器swg生成，请勿手动修改。"),
      ...MBase.toCommonNote(`命令行中执行 '${cmd["cmd"]}' 将重新生成。`),
      "\t",
    ];
  }

  /**清空文件 */
  protected async clearFiles() {
    const { dir } = this;
    await MFile.deletePath(dir);
  }
}
